package <%- entityAbsolutePackage %>.<%_ if(jpaMetamodelFiltering && reactive) { _%>domain<%_ } else { _%>service<%_ } _%>.criteria;

import static org.assertj.core.api.Assertions.assertThat;

import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.Objects;
import org.assertj.core.api.Condition;
import org.junit.jupiter.api.Test;

class <%- entityClass %>CriteriaTest {

    @Test
    void new<%- entityClass %>CriteriaHasAllFiltersNullTest() {
        var <%- persistInstance %>Criteria = new <%- entityClass %>Criteria();
        assertThat(<%- persistInstance %>Criteria).is(criteriaFiltersAre(Objects::isNull));
    }

    @Test
    void <%- persistInstance %>CriteriaFluentMethodsCreatesFiltersTest() {
        var <%- persistInstance %>Criteria = new <%- entityClass %>Criteria();

        setAllFilters(<%- persistInstance %>Criteria);

        assertThat(<%- persistInstance %>Criteria).is(criteriaFiltersAre(Objects::nonNull));
    }

    @Test
    void <%- persistInstance %>CriteriaCopyCreatesNullFilterTest() {
        var <%- persistInstance %>Criteria = new <%- entityClass %>Criteria();
        var copy = <%- persistInstance %>Criteria.copy();

        assertThat(<%- persistInstance %>Criteria).satisfies(
            criteria -> assertThat(criteria).is(copyFiltersAre(
                copy,
                (a, b) -> (a == null || a instanceof Boolean) ? a == b : (a != b && a.equals(b))
            )),
            criteria -> assertThat(criteria).isEqualTo(copy),
            criteria -> assertThat(criteria).hasSameHashCodeAs(copy)
        );

        assertThat(copy).satisfies(
            criteria -> assertThat(criteria).is(criteriaFiltersAre(Objects::isNull)),
            criteria -> assertThat(criteria).isEqualTo(<%- persistInstance %>Criteria)
        );
    }

    @Test
    void <%- persistInstance %>CriteriaCopyDuplicatesEveryExistingFilterTest() {
        var <%- persistInstance %>Criteria = new <%- entityClass %>Criteria();
        setAllFilters(<%- persistInstance %>Criteria);

        var copy = <%- persistInstance %>Criteria.copy();

        assertThat(<%- persistInstance %>Criteria).satisfies(
            criteria -> assertThat(criteria).is(copyFiltersAre(
                copy,
                (a, b) -> (a == null || a instanceof Boolean) ? a == b : (a != b && a.equals(b))
            )),
            criteria -> assertThat(criteria).isEqualTo(copy),
            criteria -> assertThat(criteria).hasSameHashCodeAs(copy)
        );

        assertThat(copy).satisfies(
            criteria -> assertThat(criteria).is(criteriaFiltersAre(Objects::nonNull)),
            criteria -> assertThat(criteria).isEqualTo(<%- persistInstance %>Criteria)
        );
    }

    @Test
    void toStringVerifier() {
        var <%- persistInstance %>Criteria = new <%- entityClass %>Criteria();

        assertThat(<%- persistInstance %>Criteria).hasToString("<%- entityClass %>Criteria{}");
    }

    private static void setAllFilters(<%- entityClass %>Criteria <%- persistInstance %>Criteria) {
<%_ for (const { propertyJavaFilterName } of entityJavaFilterableProperties) { _%>
        <%- persistInstance %>Criteria.<%- propertyJavaFilterName %>();
<%_ } _%>
        <%- persistInstance %>Criteria.distinct();
    }

    private static Condition<<%- entityClass %>Criteria> criteriaFiltersAre(Function<Object, Boolean> condition) {
        return new Condition<>(
            criteria ->
<%_ for (const { propertyJavaFilterJavaBeanName } of entityJavaFilterableProperties) { _%>
                condition.apply(criteria.get<%- propertyJavaFilterJavaBeanName %>()) &&
<%_ } _%>

                condition.apply(criteria.getDistinct()),
                "every filter matches"
        );
    }

    private static Condition<<%- entityClass %>Criteria> copyFiltersAre(<%- entityClass %>Criteria copy, BiFunction<Object, Object, Boolean> condition) {
        return new Condition<>(
            criteria ->
<%_ for (const { propertyJavaFilterJavaBeanName } of entityJavaFilterableProperties) { _%>
                condition.apply(criteria.get<%- propertyJavaFilterJavaBeanName %>(), copy.get<%- propertyJavaFilterJavaBeanName %>()) &&
<%_ } _%>
                condition.apply(criteria.getDistinct(), copy.getDistinct()),
                "every filter matches"
        );
    }

}
